package com.flyiu.data.consistency.aspect;

import java.lang.reflect.Method;

import org.apache.commons.beanutils.PropertyUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.flyiu.data.consistency.annotations.DistributedTransaction;
import com.flyiu.data.consistency.service.DistributeService;
import com.flyiu.data.consistency.synchronization.DistributedTransactionSynchronization;

/**
 * 本地事务之后开启
 * 
 * @author flyiu
 *
 */
@Aspect
@Component
//@Order(100000)
@Order
public class DistributedTransactionAspect {
	@Autowired
	private DistributeService service;

	@Autowired
	private DistributedTransactionSynchronization synchronization;

	/**
	 * 获取businessId
	 * 
	 * @param distributedTransaction
	 * @param args
	 * @return 业务businessId,如果未设置keyName及keyIndex将以当前时间做为businessId
	 * @throws Exception
	 */
	private String getBusinessId(DistributedTransaction distributedTransaction, Object[] args) throws Exception {
		String keyName = distributedTransaction.keyName();

		String businessId = System.currentTimeMillis() + "";

		if (distributedTransaction.keyIndex() >= 0) {
			Object obj = args[distributedTransaction.keyIndex()];
			if (!StringUtils.isEmpty(keyName)) {
				businessId = PropertyUtils.getProperty(obj, keyName)+"";
			} else {
				businessId = obj + "";
			}
		}
		return businessId;
	}

	/**
	 * 一阶段对象操作入库
	 *
	 * @param joinPoint
	 *            切面链接点
	 * @return 结果对象
	 * @throws Throwable
	 *             异常信息
	 */
	@Around("com.flyiu.data.consistency.aspect.DistributedTransactionPointCut.distributedTransactionPointcut()")
	public Object invokeAction(ProceedingJoinPoint joinPoint) throws Throwable {
		
		Assert.isTrue(TransactionSynchronizationManager.isActualTransactionActive(), "使用分布式事务，本地事务必须首先开启!");
		
		Signature signature = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method method = methodSignature.getMethod();
		DistributedTransaction distributedTransaction = AnnotationUtils.findAnnotation(method,
				DistributedTransaction.class);

		String businessId = getBusinessId(distributedTransaction, joinPoint.getArgs());
		service.start(distributedTransaction.name(), businessId);

		TransactionSynchronizationManager.registerSynchronization(synchronization);
		return joinPoint.proceed();
	}
}
